package apis

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-admin-team/go-admin-core/sdk/api"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/wechat/v3"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
	"tuowei.com/app/admin/models"
	admin "tuowei.com/app/admin/service"
	admindto "tuowei.com/app/admin/service/dto"
	apimodels "tuowei.com/app/api/models"
	"tuowei.com/app/api/service"
	apiservice "tuowei.com/app/api/service"
	"tuowei.com/app/api/service/dto"
	apidto "tuowei.com/app/api/service/dto"
	"tuowei.com/common/actions"
	"tuowei.com/pkg/xlog"
)

type ApiWxPay struct {
	api.Api
	Base
}

func (e ApiWxPay) Pay(c *gin.Context) {
	req := dto.WxPayReq{}
	s := service.WxPay{}
	err := e.MakeContext(c).Bind(&req, binding.JSON).MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, errors.New("参数错误"), err.Error())
		return
	}

	params, err := s.AppPay(e.Context, &req)
	if err != nil {
		xlog.Error(err)
		e.Error(500, errors.New("支付参数错误"), err.Error())
		return
	}

	e.OK(gin.H{"pay_params": params}, "支付参数获取成功")
	return
}

func (e ApiWxPay) Notify(c *gin.Context) {
	s := service.WxPay{}
	err := e.MakeContext(c).MakeService(&s.Service).MakeOrm().Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	body, _ := ioutil.ReadAll(c.Request.Body)
	b, result := service.DecodeNotify(body)
	if !b {
		xlog.Error("ApiWxPay body DecodeNotify")
		e.Error(500, errors.New("参数错误"), err.Error())
		return
	}
	xlog.Infof("ApiWxPay Notify result:%+v", result)
	//xlog.Info("=========")
	//var result wechat.V3DecryptResult
	//err = s.Notify(e.Context, &result)
	//if err != nil {
	//	xlog.Error(err)
	//	e.Error(500, errors.New("参数错误"), err.Error())
	//	return
	//}
	//
	//xlog.Infof("ApiWxPay Notify result=====================================:%+v", result)
	//// 合单支付通知解密
	//result, err := notifyReq.DecryptCombineCipherText(apiV3Key)
	//// 退款通知解密
	//result, err := notifyReq.DecryptRefundCipherText(apiV3Key)

	// ========异步通知应答========
	// 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功，否则会重试。
	// 注意：重试过多会导致微信支付端积压过多通知而堵塞，影响其他正常通知。

	// 此写法是 gin 框架返回微信的写法
	c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
	//更新订单状态为已付款，增加用户积分
	outTradeNo := result.OutTradeNo
	orderType := result.Attach
	amountTotal := result.Amount.Total
	//outTradeNo := result.OutTradeNo
	//orderType := result.Attach //商品类型OnlineOrder，MaterialOrder,LiveOrder
	total := float64(amountTotal) / float64(100)
	//解析body数据到这个结构体
	switch orderType {
	case "onlineorder":
		orderType = "OnlineOrder"
	case "liveorder":
		orderType = "LiveOrder"
	case "materialorder":
		orderType = "MaterialOrder"
	default:
		xlog.Errorf("aliPayReq.OrderType err,aliPayReq.OrderType:%s\n", orderType)
		return
	}
	//更新订单状态
	sysOrder := SysOrder{}
	switch orderType {
	case "OnlineOrder", "LiveOrder":
		reqo := admindto.UpdateOnlineOrderRequest{}
		reqo.OrderNumber = outTradeNo
		reqo.Status = 2
		sysOrder.UpdateOnlineOrderInternal(e.Context, reqo)
		//更新linkorder
		err := e.Orm.Table("sys_link_order").Where("order_number=?", outTradeNo).Update("status", 5).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
	case "MaterialOrder":
		reqm := admindto.UpdateMaterialOrderRequest{}
		reqm.OrderNumber = outTradeNo
		reqm.Status = 3
		sysOrder.UpdateMaterialOrderInternal(e.Context, reqm)
		//更新linkorder
		err := e.Orm.Table("sys_link_order").Where("order_number=?", outTradeNo).Update("status", 3).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
	default:
		xlog.Errorf("wxPayReq.OrderType err,wxPayReq.OrderType:%s\n", orderType)
		return
	}

	//根据订单id查询到买家id，
	tableName := ""
	switch orderType {
	case "OnlineOrder", "LiveOrder":
		tableName = "sys_online_order"
	case "MaterialOrder":
		tableName = "sys_material_order"
	default:
		xlog.Errorf("wxPayReq.OrderType err,wxPayReq.OrderType:%s\n", orderType)
		return

	}
	type Paydb struct {
		Id      int `json:"id"`
		BuyerId int `json:"buyer_id"`
	}
	paydb := &Paydb{}
	err = e.Orm.Table(tableName).Select("id", "buyer_id").Where("order_number=?", outTradeNo).Scan(paydb).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	if paydb.BuyerId == 0 {
		xlog.Errorf("db outTradeNo: %s;buyerId:%d", outTradeNo, paydb.BuyerId)
		return
	}
	//线上课程填充班级id
	onlineClassId := 0
	//只有在线课程才需要学习
	if orderType == "OnlineOrder" {
		//添加learning-list 订单付款成功之后再入库
		courseId := make([]int, 0)
		err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
		if len(courseId) > 0 {
			for _, c := range courseId {
				var data models.SysCourse
				err = e.Orm.Debug().Table(data.TableName()).Where("course_id = ?", c).
					First(&data).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return
				}
				onlineClassId = data.OnlineClassId
				//添加learning-list
				s1 := apiservice.ApiLearningList{}
				s1.Orm = e.Orm
				req1 := apidto.SysLearningListInsertReq{}
				req1.BuyerId = paydb.BuyerId
				req1.CourseId = c
				req1.Name = data.Name
				req1.Cover = data.Cover
				req1.Subject = data.Subject

				list := &apimodels.SysLearningList{}
				err = s1.Insert(&req1, list)
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return
				}
			}
		}
	}
	// 更新学员为正式学员
	err = e.Orm.Table("sys_student").Where("id = ?", paydb.BuyerId).Update("buy_status", 2).Error
	if err != nil {
		xlog.Errorf("变更学员id = %s为正式学员失败:", paydb.BuyerId)
	}
	//增加积分
	float := total

	sysScore := SysScore{}
	reqs := dto.SysScoreInsertReq{}
	reqs.BuyerId = paydb.BuyerId
	reqs.OrderNumber = outTradeNo
	reqs.ScoreChange = float
	reqs.Change = 1
	reqs.OrderType = orderType
	sysScore.AddScoreInternal(e.Context, reqs)
	//更新学生消费总金额
	type TotalPayS struct {
		TotalPay float64 `json:"total_pay"`
		Name     string  `json:"name"`
		UserType string  `json:"user_type"`
	}
	totalPayS := &TotalPayS{}
	err = e.Orm.Table("sys_student").Select("total_pay", "name").Where("id=?", paydb.BuyerId).Scan(&totalPayS).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	if tableName == "sys_online_order" {
		if totalPayS.UserType != "线下" && totalPayS.UserType != "线上" {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "线上").Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}
		if onlineClassId != 0 {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("class_id", onlineClassId).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}

	} else if tableName == "sys_material_order" {
		if totalPayS.UserType == "" {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "-").Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}
	}
	totalPayS.TotalPay = totalPayS.TotalPay + float*100
	if totalPayS.TotalPay > 0.00 {
		err := e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("total_pay", totalPayS.TotalPay).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
	}
	ccom := models.SysConfigCommission{}
	err = e.Orm.Table(ccom.TableName()).First(&ccom).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	//根据分享者id， 只有特殊返佣，只有网课才会给分享者返佣，其他的一律按照上级来
	if orderType == "OnlineOrder" {
		type Sharedb struct {
			ShareId       int `json:"share_id"`
			IsBindOffline int `json:"is_bind_offline"`
		}
		sharedb := &Sharedb{}
		err = e.Orm.Table("sys_online_order").Select("share_id", "is_bind_offline").Where("order_number=?", outTradeNo).Scan(sharedb).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
		if sharedb.ShareId != 0 && sharedb.IsBindOffline == 1 {
			userLabel := ""
			err = e.Orm.Table("sys_student").Select("user_label").Where("id=?", sharedb.ShareId).Scan(&userLabel).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			//校验该网课id是否属于vip等级管理的特殊返佣课程集合里面，否则不返佣
			courseId := make([]int, 0)
			err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			if len(courseId) > 0 {
				xlog.Errorf("该订单关联的课程为0,order_id:%s", paydb.Id)
				return
			}
			//返佣比例
			commissionPercentage := 0.00

			//分享人用户类型，普通，vip，svip
			switch userLabel {
			case "普通":
				if !strings.Contains(ccom.UserCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-普通,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = ccom.UserCommissionPerSpecial
			case "VIP":
				if !strings.Contains(ccom.VipCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-vip,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = ccom.VipCommissionPercentageSpecial
			case "SVIP":
				if !strings.Contains(ccom.SVipCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-svip,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = ccom.SVipCommissionPercentageSpecial
			default:
				xlog.Errorf("db userLabel: %s;sharedb.ShareId:%d", userLabel, sharedb.ShareId)
				return
			}
			//佣金计算
			com := float * commissionPercentage
			//分佣加余额
			reqB := dto.SysPayBalanceReq{}
			reqB.Balance = float32(com)
			reqB.Change = 1
			reqB.Title = "邀请人-" + totalPayS.Name
			reqB.OrderType = orderType
			reqB.OrderNumber = outTradeNo
			sB := service.ApiStudent{}
			sB.Orm = e.Orm

			err = sB.UpdatePayBalance(&reqB, sharedb.ShareId, c)
			if err != nil {
				xlog.Error(err)
				e.Error(500, err, err.Error())
				return
			}
			//订单更新返佣
			err = e.Orm.Table(tableName).Where("order_number=?", outTradeNo).Updates(map[string]interface{}{"commission": com}).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			return
		}
	}
	//买家id查询上级是否为学生，等级
	recommender := 0
	err = e.Orm.Table("sys_student").Select("recommender").Where("id=?", paydb.BuyerId).Scan(&recommender).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	if recommender == 0 {
		//xlog.Errorf("db buyerId: %s;recommender:%d", paydb.BuyerId, recommender)
		return
	}
	userLabel := ""
	err = e.Orm.Table("sys_student").Select("userLabel").Where("id=?", recommender).Scan(&userLabel).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	//返佣比例
	commissionPercentage := 0.00

	//推荐人用户类型，普通，vip，svip
	switch userLabel {
	case "普通":
		commissionPercentage = ccom.UserCommissionPer
	case "VIP":
		commissionPercentage = ccom.VipCommissionPercentage
	case "SVIP":
		commissionPercentage = ccom.SVipCommissionPercentage
	default:
		xlog.Errorf("db userLabel: %s;recommender:%d", userLabel, recommender)
		return
	}
	//佣金计算
	com := float * commissionPercentage
	//分佣加余额
	reqB := dto.SysPayBalanceReq{}
	reqB.Balance = float32(com)
	reqB.Change = 1
	reqB.Title = "邀请人-" + totalPayS.Name
	reqB.OrderType = orderType
	reqB.OrderNumber = outTradeNo
	sB := service.ApiStudent{}
	sB.Orm = e.Orm

	err = sB.UpdatePayBalance(&reqB, recommender, c)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	//订单更新返佣
	err = e.Orm.Table(tableName).Where("order_number=?", outTradeNo).Updates(map[string]interface{}{"commission": com}).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	return
}

//func (e ApiWxPay) Notify1(c *gin.Context) {
//	wxPayReq := &dto.WxPayReq{}
//	wxPayReq.OrderSn = "e438ab26-1a65-4a85-8c12-7babb282c775"
//	wxPayReq.OrderType = "MaterialOrder"
//	url := ""
//	//更新订单状态
//	switch wxPayReq.OrderType {
//	case "OnlineOrder", "LiveOrder":
//		url = "http://localhost:8000/api/v1/api-order/update/online/order"
//	case "MaterialOrder":
//		url = "http://localhost:8000/api/v1/api-order/update/material/order"
//	default:
//		xlog.Errorf("wxPayReq.OrderType err,wxPayReq.OrderType:%s\n", wxPayReq.OrderType)
//		return
//
//	}
//	contentType := "application/json"
//	u := &UpdateOrderStatus{
//		OrderNumber: wxPayReq.OrderSn,
//		Status:      2,
//	}
//	xlog.Infof("UpdateOrderStatus:%+v", u)
//	data, err := json.Marshal(u)
//	if err != nil {
//		xlog.Errorf("UpdateOrderStatus Marshal, err:%v\n", err)
//		return
//	}
//	_, err = http.Post(url, contentType, bytes.NewBuffer(data))
//	if err != nil {
//		xlog.Errorf("post failed, err:%v\n", err)
//		return
//	}
//}

func (e ApiWxPay) Transfer(c *gin.Context) {
	req := dto.TransferReq{}
	s := service.WxPayWechat{}
	s1 := admin.SysConfigCommission{}
	s2 := service.SysBalanceDetail{}
	s3 := admin.SysFinanceTxmx{}
	s4 := admin.SysStudent{}
	err := e.MakeContext(c).Bind(&req, binding.JSON).MakeOrm().
		MakeService(&s.Service).
		MakeService(&s1.Service).
		MakeService(&s2.Service).
		MakeService(&s3.Service).
		MakeService(&s4.Service).
		Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, errors.New("参数错误"), err.Error())
		return
	}
	err, req.StudentId = e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	//数据权限检查
	p := actions.GetPermissionFromContext(c)

	list := models.SysConfigCommission{}

	err = s1.Get(p, &list)

	if err != nil {
		e.Error(500, err, "查询失败")
		return
	}

	if req.Amount < list.MinWithdraw {
		str := fmt.Sprintf("最低提现金额为%0.2f", list.MinWithdraw)
		err = errors.New(str)
		e.Error(500, err, str)
		return
	}
	var student models.TransferStudent
	res, result, err := s.Transfer(&req, &student)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	if result.Response.StatusCode != http.StatusOK {
		e.Error(500, errors.New(result.Response.Status), result.Response.Status)
		return
	}
	balanceDetail := &dto.SysBalanceDetailInsertReq{
		BuyerId:       req.StudentId,
		Title:         "余额提现",
		BalanceChange: req.Amount,
		BalanceSum:    student.Balance - req.Amount,
		Change:        3,
	}
	s2.Orm = s1.Orm
	go s2.Insert(balanceDetail)

	//insert 提现明细
	tx := &admindto.SysFinanceTxmxInsertReq{}
	var object models.SysStudent
	reqs := admindto.SysStudentById{}
	reqs.Id = req.StudentId
	err = s4.Get(&reqs, p, &object)
	if err != nil {
		e.Error(http.StatusUnprocessableEntity, err, "查询失败")
	} else {
		tx.Name = object.Name
		tx.Account = object.Phone

		tx.UserType = object.UserLabel
		tx.AccountBalance = float64(object.Balance)
		tx.TxAmount = req.Amount
		//tx.Province = object.Province
		tx.TxTime = time.Now().Local()
		tx.TxStatus = "完成"
		tx.TxWay = 1
		go s3.Insert(tx)
	}

	e.OK(res, "转账成功")
	return
}
